package com.nt.train.processor;

import com.nt.train.annotation.CoreAnnotation;
import com.nt.train.annotation.NTService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 *
 * @author hlf
 * @version 1.0
 * @date 2022/8/12 10:50
 */
@Component
public class NtServiceDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, EnvironmentAware {

    private Environment environment;

    private ResourceLoader resourceLoader;

    //根据扫描路径注册处理 方式1
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        //用扫描器根据指定注解进行扫描获取BeanDefinition
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry, false,
                environment, resourceLoader);
        scanner.addIncludeFilter(new AnnotationTypeFilter(NTService.class));

        //ClassPathBeanDefinitionScanner的扫描获取指定注解，其中findCandidateComponents方法就是指定扫描包开始位置
        String basePackage = "com" ;
        //自定义路径处理
        //basePackage=  environment.getProperty("xxxx");

        Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
        try {
            registerCandidateComponents(beanDefinitionRegistry,candidateComponents);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    //根据注解注册bean处理 方式2
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
//        try {
//            String[] serviceNames  =  configurableListableBeanFactory.getBeanNamesForAnnotation(NTService.class);
//            Arrays.stream(serviceNames).forEach(serviceName->{
//                BeanDefinition definition = configurableListableBeanFactory.getBeanDefinition(serviceName);
//                Class clazz  = null;
//                try {
//                    clazz = Thread.currentThread().getContextClassLoader().loadClass(definition.getBeanClassName());
//                } catch (ClassNotFoundException e) {
//                    e.printStackTrace();
//                }
//                NTService serviceList =(NTService) AnnotationUtils.findAnnotation(clazz,NTService.class);
//                configurableListableBeanFactory.registerAlias(serviceName,serviceList.id()+"_"+serviceList.name());
//            });
//
//        }catch (Exception e){
//            throw  new  RuntimeException(e);
//        }
    }

    /**
     * 注册 BeanDefinition
     */
    private void registerCandidateComponents(BeanDefinitionRegistry registry, Set<BeanDefinition> candidateComponents)
            throws ClassNotFoundException {
        for (BeanDefinition candidateComponent : candidateComponents) {
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
                AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                AnnotationMetadata annotationMetadata = annotatedBeanDefinition.getMetadata();
                Map<String, Object> customImportAnnotationAttributesMap = annotationMetadata.getAnnotationAttributes(
                        CoreAnnotation.class.getName());
                AnnotationAttributes customImportAnnotationAttributes = Optional.ofNullable(AnnotationAttributes.
                        fromMap(customImportAnnotationAttributesMap)).orElseGet(AnnotationAttributes::new);//获取注解里的值
                String[] values = customImportAnnotationAttributes.getStringArray("value");
                String className = annotationMetadata.getClassName();
                Class<?> clazzName = Class.forName(className);
                Arrays.asList(values).forEach(m ->{
                    RootBeanDefinition mbean = null;
                    try {
                        mbean = new RootBeanDefinition(clazzName);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    registry.registerBeanDefinition(m, mbean);
                });
            }
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;

    }
}